home *** CD-ROM | disk | FTP | other *** search
- TITLE JOYTIMER - CPU INDEPENDANT JOYSTICK READ AND TIMER SPPT
-
- COMMENT $
-
- This special cpu-speed independent joystick reader was
- written by Dave Stampe. It has about twice the resolution
- of normal joystick readers, about 1200 compared to 600.
-
- It works by counting the number of 1.19 MHz increments of
- the PC timer. This version re-reads the joystick if the
- timer rolls over: this is becasue the timer handling ISR
- could cause the end-of-count of the joystick to be missed,
- resulting in glitches.
-
- The timer routines that follow give REND386
- the ability to compile with -3 (386 instructions)
- bypassing the bugs in the _interrupt headers
- in BC 3.1. If your program uses any other routines
- and then crashes, then save all registers with an inline
- pushad and restore with popad to fix the problem.
-
- Also has a keyboard interrupt intercept which can
- monitor key status directly
-
- /*
- This code is part of the VR-386 project, created by Dave Stampe.
- VR-386 is a desendent of REND386, created by Dave Stampe and
- Bernie Roehl. Almost all the code has been rewritten by Dave
- Stampre for VR-386.
-
- Copyright (c) 1994 by Dave Stampe:
- May be freely used to write software for release into the public domain
- or for educational use; all commercial endeavours MUST contact Dave Stampe
- (dstampe@psych.toronto.edu) for permission to incorporate any part of
- this software or source code into their products! Usually there is no
- charge for under 50-100 items for low-cost or shareware products, and terms
- are reasonable. Any royalties are used for development, so equipment is
- often acceptable payment.
-
- ATTRIBUTION: If you use any part of this source code or the libraries
- in your projects, you must give attribution to VR-386 and Dave Stampe,
- and any other authors in your documentation, source code, and at startup
- of your program. Let's keep the freeware ball rolling!
-
- DEVELOPMENT: VR-386 is a effort to develop the process started by
- REND386, improving programmer access by rewriting the code and supplying
- a standard API. If you write improvements, add new functions rather
- than rewriting current functions. This will make it possible to
- include you improved code in the next API release. YOU can help advance
- VR-386. Comments on the API are welcome.
-
- CONTACT: dstampe@psych.toronto.edu
- */
-
- /* Joystick reader (c) 1993 by Dave Stampe
- /* Contact: dstampe@sunee.waterloo.edu */
-
- $
-
- .MODEL large
- .386
-
- extrn _vsync:PROC ; waits for vert. sync
-
- .DATA
-
- PUBLIC _joystick_j1
- PUBLIC _joystick_j2
- PUBLIC _joystick_j3
- PUBLIC _joystick_j4
- PUBLIC _joystick_buttons
-
- _joystick_j1 dw 0 ; /* raw joystick results */
- _joystick_j2 dw 0
- _joystick_j3 dw 0
- _joystick_j4 dw 0
- _joystick_buttons dw 0
-
-
- .CODE devices
-
-
- READ_TIMER MACRO ; result will be in ax
- pushf
- cli
- mov al,00h ;/* read PC timer */
- out 043h,al
- nop
- nop
- in al,040h
- mov ah,al
- nop
- nop
- in al,040h
- xchg al,ah
- popf
- ENDM
-
- WRITE_TIMER MACRO ; write from BX
- pushf
- cli
- mov al,34h
- out 43h,al ; prepare for write
- xor al,al
- nop
- mov al,bl
- out 40h,al
- nop
- mov al,bh
- out 40h,al
- popf
- ENDM
-
-
- ;/********* READ JOYSTICK (RAW COUNT) ************/
-
-
- mask equ [bp+8] ; arguments
-
- vj1 equ [bp-2] ; locals
- vj2 equ [bp-4]
- vj3 equ [bp-6]
- vj4 equ [bp-8]
- raw equ [bp-10]
- last_time equ [bp-12]
- abort equ [bp-14]
-
-
- ;int raw_joystick_read(int mask) ; fills variables, returns 0 if OK
- ; if failure, retry later on
-
- PUBLIC _raw_joystick_read
-
- _raw_joystick_read proc far
-
- .386
- push ebp
- mov ebp,esp
- sub esp,20
- pushf
- push dx
-
- test BYTE PTR mask,-1
- je quit_now
-
- xor ax,ax
- mov vj1,ax
- mov vj2,ax
- mov vj3,ax
- mov vj4,ax
- mov cx,5000 ;/* safety timer limit */
-
- waitforit:
- mov dx,0201h ;/* wait for timers clear
- in al,dx
- and al,0Fh
- and al,mask
- je ready_to_begin
- loop waitforit
- jmp quit_now ; no joystick: abort!
-
- ready_to_begin:
- cli
- mov dx,0201h ;/* start game port timers */
- mov al,0ffh
- out dx,al
-
- READ_TIMER ; read PC timer count
- mov last_time,ax
-
- in al,dx ;/* record game port value */
- mov raw,al
- and al,mask
- mov bl,al
- je timeout ;/* catch very short joy time */
- mov cx,4000 ;/* safety timer limit */
- sti
- wloop:
- sti ;/* allow ints to occur here */
- cli
- in al,dx
- mov raw,al ;/* game port change? */
- and al,mask
- xor al,bl
- and al,mask
- jne timeout
-
- loop wloop ;/* safety timer overflow? */
-
- sti
- jmp quit_now
-
- mov al,mask
- not al
- mov raw,al
- mov abort,ax ; abort, no bits changed
-
- timeout:
- mov bl,raw ;/* record change */
- mov bh,al
-
- READ_TIMER ; read PC timer count
- sti
-
- test word ptr long_interrupt,-1
- jne quit_now
- sub ax,last_time ;/* compute delay */
- neg ax
- jge posj
- add ax,_counts_per_tick ; fixup for timer rollover
- posj:
- cmp ax,1400
- ja quit_now ; timer rollover unrecoverable! exit.
-
- test bh,8 ;/* update proper joy values */
- je ns4
- mov vj4,ax
- ns4:
- test bh,4
- je ns3
- mov vj3,ax
- ns3:
- test bh,2
- je ns2
- mov vj2,ax
- ns2:
- test bh,1
- je ns1
- mov vj1,ax
- ns1:
- mov al,raw ;/* check if all bits done */
- not al
- and al,mask
- cmp al,mask
- jne wloop
-
- shorttime:
- mov ax,vj1 ; copy final values
- mov _joystick_j1,ax
- mov ax,vj2
- mov _joystick_j2,ax
- mov ax,vj3
- mov _joystick_j3,ax
- mov ax,vj4
- mov _joystick_j4,ax
-
- mov ax,raw ; extract button flags
- not ax
- shr ax,4
- and ax,0Fh
- mov _joystick_buttons,ax
- mov ax,0
-
- pop dx
- popf
- mov esp,ebp ; 0: successful read
- pop ebp
- ret
-
- quit_now:
- mov word ptr long_interrupt,0
- mov ax,cx
- inc ax ; will be 1 if too long, else timer ovf
-
- pop dx
- popf
- mov esp,ebp
- pop ebp
- ret
-
- _raw_joystick_read endp
-
-
- ;/************ TIMER HANDLING DATA ************/
-
- .DATA
-
- PUBLIC _timer_tick_count
- PUBLIC _timer_vsync_count
- PUBLIC _ticks_per_second
- PUBLIC _counts_per_tick
-
- _timer_tick_count dd 0 ; number of interrupts so far
- _timer_vsync_count dw 20000 ; timer counts per video frame
- _ticks_per_second dw 1000 ; counter time basis
- _counts_per_tick dw 65535 ; counter time basis
-
- PUBLIC _timer_interrupt_hook
- PUBLIC _frame_interrupt_hook
-
- _timer_interrupt_hook dd 0 ; timer tick interrupt
- _frame_interrupt_hook dd 0 ; frame-end interrupt (arg=0)
-
- PUBLIC _timer_frame_interval
- PUBLIC _frame_resync_interval
-
- _timer_frame_interval dw 0 ; number of timer ticks per frame
- _frame_resync_interval dw 5 ; number of frames between resyncs
-
- divisor dw 0 ; used to compute DOS interrupt interval
- frame_count dw 0 ; number of timer ticks to end of frame
- frame_sync dw 0 ; number of frames till sync
-
- long_interrupt dw 0 ; set if processing took too long
-
- ;/************* KEYBOARD MONITOR DATA *************/
-
- ;;;PUBLIC _keyflags only for debug!
-
- _keyflags db 20 dup (0) ; room for 128 keycodes
-
- .CODE devices
-
-
- ;/************* TIMER SUPPORT ***************/
-
- ;unsigned find_vsync_count() // finds timer clocks per frame
-
- PUBLIC _find_vsync_count
- _find_vsync_count proc far
-
- .386
- push ebp
- mov ebp,esp
-
- cli
- xor bx,bx
- WRITE_TIMER ; set timer for no overflow
-
- sti
-
- call far ptr _vsync ; time of frame start
- cli
- READ_TIMER
- push ax
- call far ptr _vsync ; 2xframe delay
- call far ptr _vsync
- READ_TIMER ; time of end
- sti
- pop bx
- sub bx,ax
- shr bx,1
- mov ax,bx ; compute count
-
- mov esp,ebp
- pop ebp
- ret
-
- _find_vsync_count endp
-
-
-
- ;void write_timer(unsigned count) // sets timer period, restarts count
-
-
- count equ [bp+8]
-
- PUBLIC _write_timer
-
- _write_timer proc far
-
- .386
- push ebp
- mov ebp,esp
-
- mov bx,count
- WRITE_TIMER
-
- mov esp,ebp
- pop ebp
- ret
-
- _write_timer endp
-
-
-
- ;unsigned read_timer(); // reads current timer count
-
- PUBLIC _read_timer
-
- _read_timer proc far
-
- .386
- push ebp
- mov ebp,esp
-
- READ_TIMER
-
- mov esp,ebp
- pop ebp
- ret
-
- _read_timer endp
-
-
- ;/*********** TIMER ISR *************/
-
- ;void timer_isr() ; does timer interrupt stuff
-
- PUBLIC _timer_isr
-
- _timer_isr proc far
-
- .386
- pushf
- pushad
- push ds
- push es
- push fs
- push gs
-
- cli
- mov al,20h
- out 20h,al ; nonspecific EOI to PIC
-
- mov ax,DGROUP
- mov ds,ax
-
- inc DWORD PTR _timer_tick_count
-
- sub WORD PTR frame_count,1 ; end of frame?
-
- test DWORD PTR _frame_interrupt_hook,-1 ; frame sync on?
- je no_frame
- inc word ptr long_interrupt
- push WORD PTR frame_count ; frame interrupt hook
- call DWORD PTR _frame_interrupt_hook
- add esp,2
-
- cmp WORD PTR frame_count,0 ; end of frame?
- jg no_frame
-
- sub WORD PTR frame_sync,1
- jg no_frame
- mov ax,_frame_resync_interval ; SYNC INTERVAL
- mov frame_sync,ax
-
- inc word ptr long_interrupt
- mov bx,0 ; resync timer
- WRITE_TIMER
- call far ptr _vsync
- mov bx,_counts_per_tick
- WRITE_TIMER
-
- no_frame:
- test DWORD PTR _timer_interrupt_hook,-1
- je no_timer_call
- inc word ptr long_interrupt
- push WORD PTR frame_count ; timer tick hook
- call DWORD PTR _timer_interrupt_hook
- add esp,2
- no_timer_call:
- ; reset this AFTER for proper args
- cmp WORD PTR frame_count,0
- jg notfreset
- mov ax,_timer_frame_interval
- mov frame_count,ax
- notfreset:
- mov ax,divisor
- add ax,_counts_per_tick ; time to fake 18.2 Hz?
- mov divisor,ax
- jnc not_DOS_time
-
- int 78h ; call old ISR
-
- not_DOS_time: ; no, get out
- pop gs
- pop fs
- pop es
- pop ds
- popad
- popf
- iret
-
- _timer_isr endp
-
-
- ;/********* RETURN CURRENT TIME IN MILLISECONDS *********/
-
- ;long current_time() ; returns time in msec
-
- PUBLIC _current_time
-
- _current_time proc far
-
- .386
- push ebp
- mov ebp,esp
-
- pushf
- cli
- READ_TIMER
- movzx ebx,ax
- mov eax,_timer_tick_count
- movzx edx,WORD PTR _counts_per_tick
- popf
-
- imul edx ; total count compute
- add eax,ebx
- adc edx,0
-
- mov ebx,1190 ; compute milliseconds
- idiv ebx
- shld edx,eax,16 ; return value in eax and dx:ax
-
- mov esp,ebp
- pop ebp
- ret
-
- _current_time endp
-
-
-
- ;/************* KEYBOARD MONITOR *************/
-
-
- ; int is_key_down(unsigned keycode) // returns 1 if key down
-
- keycode equ WORD PTR [bp+8] ; arguments
-
- PUBLIC _is_key_down
-
- _is_key_down proc far
-
- .386
- push ebp
- mov ebp,esp
-
- mov cx,keycode ; isolate bit
- mov bx,cx
- xor bh,bh
- shr bx,3
- and cx,7
- mov al,ds:_keyflags[bx]
- shl al,cl ; 0 is msb, 7 is lsb
- and ax,80h
-
- mov esp,ebp
- pop ebp
- ret
-
- _is_key_down endp
-
-
-
- ;/*********** KBRD INTERCEPT ISR *************/
-
- ;void kbrd_isr() ; intercepts kbrd interrupt, records key state
-
- PUBLIC _kbrd_isr
-
- _kbrd_isr proc far
- pushf
- pushad
- push ds
-
- cli
-
- mov ax,DGROUP
- mov ds,ax
-
- xor ax,ax
- in al,60h ; get key code
- mov dx,ax
- and ax,07fh
- mov bx,ax
- mov cx,ax
-
- cmp ax,60h ; extended code flag
- ja ignore_it ; ignore it, just makes keys identical
-
- shr bx,3 ; offset in table
- and cl,7 ; bit shift
- mov ax,080h
- shr ax,cl ; create bit mask: 0 is msb
-
- test dx,80h ; msb set if keyup even else keydown
- jnz clear_bit
-
- or BYTE PTR ds:_keyflags[bx],al
- jmp done_kbrd
-
- clear_bit:
- not al
- and BYTE PTR ds:_keyflags[bx],al
-
- ignore_it:
- done_kbrd:
-
- int 79h ; call old kbrd isr
-
- pop ds
- popad
- popf
- iret
-
- _kbrd_isr endp
-
- end
-